package com.hup.utils.swing.customView.colorChooser;

import com.hup.utils.commons.start.LookThemeUtil;
import lombok.extern.log4j.Log4j2;

import java.awt.*;
import java.awt.image.MemoryImageSource;
import java.util.Objects;

/**
 * [亮度]色板
 * <pre>
 * '亮度值'增加时[0->255],越大越亮;与idea的亮度值是相反的
 * 算法:
 *   传入颜色RGB中,'值最大的位'的值是当前亮度值,这里定义为[亮度位];
 *   [当前颜色]在色板上的X坐标百分比=[(当前亮度+1)/256];
 *   由上推出
 *      .色板最右边亮度值恒定是255,其RGB取值等于:[当前颜色RGB]/[X坐标百分比]
 *      .色板最左边是(0,0,0)
 *      .色板从右向左,按[色位各自的步长]线性递减,步长=[色位最大值-色位最小值0+1]/256
 * 算法来源:
 *   来自PS-CS6的颜色选择器的亮度条
 * </pre>
 * @author hugan
 * @date 2020/4/10
 */
@Log4j2
public class BrightnessLabel extends AbsColorLabel {

    /**
     * 亮度值:[0,255]
     */
    private int brightness;
    /**
     * 当前颜色的最大值所在的位置[0,1,2]->[r,g,b]
     */
    private int maxType;

    public BrightnessLabel() {
        Dimension dimension = new Dimension(-1, (int) (25 * LookThemeUtil.getScreenScale()));
        setPreferredSize(dimension);
        setMinimumSize(dimension);
    }

    @Override
    protected int[] initPix() {
        return new int[256];
    }

    @Override
    protected boolean needUpdateImage(Color newer, Color older) {
        for (int i : pix) {
            if (Objects.equals(i, newer.getRGB())) {
                brightness = getBrightness(newer);
                /*
                实现,反复拖拽亮度条后,颜色不会变成黑色
                如果是因为拖拽本色板触发的更新颜色,则不应该更新色板
                 */
                log.debug("来自本色板的颜色,不更新本色板");
                return false;
            }
        }
        log.debug("更新色板");
        return true;
    }

    @Override
    protected Image updateImageByColor() {
        //详见类注释的算法说明
        brightness = getBrightness(color);
        int a = color.getAlpha();//保留当前透明度

        double curPercent = (brightness + 1) / 256.0;//当前颜色的位置
        int curPercentI = brightness;
        log.debug("curPercentI={}", curPercentI);
        int r0 = color.getRed();
        int g0 = color.getGreen();
        int b0 = color.getBlue();
        //如果'色位'是当前[亮度位],则直接是255;否则,按百分比计算;有可能多位同位[亮度位]
        int maxR = r0 != brightness ? (int) (r0 / curPercent) : 255;
        int maxG = g0 != brightness ? (int) (g0 / curPercent) : 255;
        int maxB = b0 != brightness ? (int) (b0 / curPercent) : 255;

        double stepR = (maxR + 1) / 256.0;
        double stepG = (maxG + 1) / 256.0;
        double stepB = (maxB + 1) / 256.0;
        log.debug("maxR={}, maxG={}, maxB={}", maxR, maxG, maxB);
        log.debug("stepR={}, stepG={}, stepB={}", stepR, stepG, stepB);

        for (int i = 0; i < pix.length; i++) {
            //这里是以[当前颜色]为中心,向左右增减:避免从[头尾]增减时,有机率丢失了当前颜色
            int step = i - curPercentI;
            int r = (int) (r0 + step * stepR);
            int g = (int) (g0 + step * stepG);
            int b = (int) (b0 + step * stepB);
            //log.info("r={}, g={}, b={}", r, g, b);
            pix[i] = a << 24 | r << 16 | g << 8 | b;
        }
        return createImage(new MemoryImageSource(pix.length, 1, pix, 0, pix.length));
    }

    @Override
    protected boolean doPaintGraphics(Graphics g) {
        g.drawImage(image, 0, 0, width, height, null);

        double perStepWid = width / (pix.length + 0d);//没个色度占的横向像素
        int curX = (int) (brightness * perStepWid);//顶点的x
        int h2 = height / 4;
        //多边形,添加坐标时要按 顺序(顺/逆时针)添加
        Polygon p = new Polygon();//倒三角
        g.setColor(CURSOR_COLOR_C1);
        p.addPoint(curX - h2, 0);//左
        p.addPoint((int) (curX + h2 + perStepWid), 0);//右
        p.addPoint((int) (curX + perStepWid), height / 6 * 2);//右底点
        p.addPoint(curX, height / 6 * 2);//左底点
        g.fillPolygon(p);

        p.reset();
        g.setColor(CURSOR_COLOR_C2);
        p.addPoint((int) (curX + perStepWid), height / 6 * 4);//右顶点
        p.addPoint(curX, height / 6 * 4);//左顶点
        p.addPoint(curX - h2, height);//左
        p.addPoint((int) (curX + h2 + perStepWid), height);//右
        g.fillPolygon(p);
        return true;
    }

    @Override
    protected Color getMouseColor(boolean isPress, int x, int y) {
        int curI = getMxIndex(x);
        return new Color(pix[curI], true);
    }

    /**
     * 微调亮度
     * @param isUp true-变亮;false-变暗
     * @param diff 要增减的亮度值[0,255]
     */
    public void shiftBrightness(boolean isUp, int diff) {
        if ((brightness == 0 && !isUp) || (brightness == 255 && isUp)) {
            //当前已经是边缘了
            return;
        }

        int index = brightness + (isUp ? diff : -diff);
        if (index < 0) {
            index = 0;
        } else if(index > 255) {
            index = 255;
        }
        log.debug("brightness={}, index={}", brightness, index);
        Color res = new Color(pix[index], true);
        log.debug("res={}", res);
        updateTo(res);
        if (colorInvoker != null) colorInvoker.fireColorChanged(this, color);
    }

}
